package org.fast.cms.security;

import java.util.List;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.fast.cms.common.utils.string.StringUtils;
import org.fast.cms.config.AdminAppProperties;
import org.fast.cms.entity.admin.SysMenu;
import org.fast.cms.entity.admin.SysRole;
import org.fast.cms.entity.admin.SysUser;
import org.fast.cms.utils.UserUtils;
import org.fast.cms.utils.ValidateCodeServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.collect.Sets;

/** 
* @author weigen.ye 
* @date 创建时间：2017年6月17日 下午12:35:48 
*
*/
@Component
public class SystemAuthorizingRealm extends AuthorizingRealm {
	
    @Autowired 
	private AdminAppProperties adminProperties;
    
	@Override
	public boolean supports(AuthenticationToken var1) {
		return var1 instanceof UsernamePasswordToken;
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		LoginUserInfo userInfo = (LoginUserInfo) getAvailablePrincipal(principals);
		SysUser user = UserUtils.getByLoginName(userInfo.getLoginName());
		if (user != null && user.getIsActivated().intValue() == 1
				&& user.getIsFrozen().intValue()==0) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			List<SysMenu> menuList = UserUtils.getMenuList();
			Set<String> permissionSet = Sets.newHashSet();
			for (SysMenu m : menuList) {
				if (StringUtils.isNotBlank(m.getPermission())) {
					permissionSet.add(m.getPermission());
				}
			}
			info.setStringPermissions(permissionSet);
			
			List<SysRole> roleList = UserUtils.getRoleList();
			Set<String> roleSet = Sets.newHashSet();
			for (SysRole m : roleList) {
				roleSet.add(m.getRoleName());
			}
			info.setRoles(roleSet);
			
			return info;
		}
		return null;
	}

	/**
	 * 认证回调函数, 登录时调用
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

		String username = token.getUsername();
		String password = String.valueOf(token.getPassword());
		
		if (adminProperties.isValidateCodeUsed()) {
			Session session = UserUtils.getSession();
			String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
			if (StringUtils.isEmpty(token.getValidateCode()) || !token.getValidateCode().toUpperCase().equals(code)) {
				throw new AuthenticationException("msg:验证码错误, 请重试.");
			}
		}
		
		if (StringUtils.isBlank(username)) {
			throw new AuthenticationException("msg:请输入用户名");
		}
		if (StringUtils.isBlank(password)) {
			throw new AuthenticationException("msg:请输入密码");
		}

		SysUser user = UserUtils.getByLoginName(token.getUsername());
		if (user == null) {
			throw new AuthenticationException("msg:用户账户不存在");
		}
		if (user.getIsActivated() != 1) {
			throw new AuthenticationException("msg:用户账户未激活");
		}
		//凭证加Salt
	    String credentialsSalt=token.getUsername()+user.getSalt();
		/**
		 * 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
		 * 可自定义CredentialsMatcher实现
		 */
	    return new SimpleAuthenticationInfo(
	    		new LoginUserInfo(user.getUserId(),token.getUsername()),
				user.getPassword(),
				ByteSource.Util.bytes(credentialsSalt),
				getName());
	}
}
